package java8.atguigu.teacher.lambda06.stream01;

import java8.atguigu.lu.l01.Employee;
import org.junit.Test;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Stream;

/**
 * @program lambda
 * @description:
 * @author: zhanglu
 * @create: 2019-05-26 22:07:00
 *
 * 一、Stream 的三个操作步骤
 *
 * 1、创建Stream
 * 2、中间操作
 * 3、终止操作(终端操作)
 *
 */
//中间操作
public class TestStreamAPI02 {

    List<Employee> employeeList = Arrays.asList(
            new Employee("张1",20,100),
            new Employee("张1",19,90),
            new Employee("张2", 21, 101),
            new Employee("张3", 22, 102),
            new Employee("张4", 23, 103),
            new Employee("张5", 24, 104),
            new Employee("张6", 25, 105)
    );

    /*
        筛选与切片
        filter - 接收lambda，从流中排除某些元素
        limit - 截断流，使用元素不超过给定数量
        skip(n) - 跳过元素，返回一个扔掉了前n个元素的流。若流中元素不足n个，则返回一个空流，与limit(n)互补
        distnct - 筛选，通过流所生成元素的hashCode()和equals()去除流重复元素
     */
    //内部迭代：迭代操作由Stream API 完成
    @Test
    public void test01(){
        //中间操作：不会执行任何操作
        /*
            多个中间操作可以连接起来形成一个流水线，除非流水线上触发终止操作，
            否则中间操作不会执任何的处理!而在终止操作时一次性全部处理，成为"惰性求值"、"延时加载"
         */
        Stream<Employee> stream1 = employeeList.stream().filter((x) -> {
            System.out.println("Stream Api 的中间操作");
            return x.getAge() > 22;
        });
        //终止操作：一次性执行全部内容
        stream1.forEach(System.out::println);
    }

    //外部迭代
    @Test
    public void test02(){
        Iterator<Employee> it = employeeList.iterator();
        while (it.hasNext()){
            System.out.println(it.next());
        }
    }

    //limit 短路
    @Test
    public void test03(){
        Stream<Employee> stream1 = employeeList.stream().filter((x) -> {
            System.out.println("短路");
            return x.getAge() > 19;
        });
        stream1.limit(2).forEach(System.out::println);
    }

    //skip跳过
    @Test
    public void test04(){
        Stream<Employee> stream1 = employeeList.stream().filter((x) -> {
            System.out.println("跳过");
            return x.getAge() > 19;
        });
        stream1.skip(2).forEach(System.out::println);
    }

    //distinct去重
    @Test
    public void test05(){
        //这里需要重写该对象的hashCode和equals方法
//        Stream<Employee> stream1 = employeeList.stream().filter((x) -> {
//            System.out.println("去重");
//            return x.getAge() > 19;
//        });
//        stream1.distinct().forEach(System.out::println);

//        employeeList.stream().filter(distinctByKey(o -> o.getName())).forEach(System.out::println);


        Map<String, Object> m = new ConcurrentHashMap<>();
        employeeList.stream().filter(o -> {
            Object o1 = m.putIfAbsent(o.getName(), 1);
            return o1 == null;
        }).forEach(System.out::println);

    }

    //去重复
    private <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
        Map<Object,Object> seen = new ConcurrentHashMap<>();
        return t -> {
            Object o = seen.putIfAbsent(keyExtractor.apply(t), 1);
            return o == null;
        };
    }

    /*
        映射
        1、map - 接收lambda,将元素转换成其他形式或提取信息。接收一个函数作为参数，该函数会被应用到每个元素上，并将其映射成一个新的元素。
        2、flatMap - 接收一个函数作为参数，将流中的每个值都转换成另一个流，然后把所有流连接成一个流
        类似于 集合中 add 与 addAll 的区别
     */
    @Test
    public void test06(){
        List<String> list = Arrays.asList("aa", "bb", "cc", "dd", "ee");
        //1、map
        list.stream()
                .map((str) -> str.toUpperCase())
                .forEach(System.out::println);

        System.out.println("---------------------------------------");
        employeeList.stream().map(str -> str.getName()).forEach(System.out::println);

        System.out.println("---------------------------------------");

        TestStreamAPI02 testStreamAPI02 = new TestStreamAPI02();
        Stream<Stream<Character>> streamStream = list.stream()
                                                    .map(testStreamAPI02::filterCharacter);
        streamStream.forEach(sm -> {
            sm.forEach(System.out::println);
        });

        System.out.println("---------------------------------------");
        //2、flatMap
        Stream<Character> stream = list.stream().flatMap(this::filterCharacter);
        stream.forEach(System.out::println);
    }

    public Stream<Character> filterCharacter(String str){
        List<Character> list = new ArrayList<>();
        for(Character ch : str.toCharArray()){
            list.add(ch);
        }
        return list.stream();
    }

    @Test
    public void test07(){
        List<String> list = Arrays.asList("aa", "bb", "cc", "dd", "ee");
        List list1 = new ArrayList();
        list1.add(11);
        list1.add(22);
//        list1.add(list);    //[11, 22, [aa, bb, cc, dd, ee]]
        list1.addAll(list);   //[11, 22, aa, bb, cc, dd, ee]
        System.out.println(list1);
    }



    /*
        排序
        sorted() - 自然排序(Comparable)
        sorted(Comparator com) - 定制排序
     */
    //自然排序
    @Test
    public void test08(){
        List<String> list = Arrays.asList("cc", "ee", "bb", "dd", "aa");
//        list.stream().sorted().forEach(System.out::println);

        employeeList.stream().sorted((e1, e2) -> e1.getAge() - e2.getAge()).forEach(System.out::println);
        System.out.println("--------");
        employeeList.stream().sorted((e1, e2) -> (e1.getAge() - e2.getAge()) * 1000 + (e1.getCount() - e2.getCount())).forEach(System.out::println);

        System.out.println("========");

        employeeList.stream().sorted((e1, e2) -> e2.getAge() - e1.getAge()).forEach(System.out::println);
        System.out.println("--------");
        employeeList.stream().sorted((e1, e2) -> (e2.getAge() - e1.getAge()) + (e2.getCount() - e1.getCount())).forEach(System.out::println);
    }


}
